function Dashboard(gtdinboxPage){
	this._gtdinboxPage = gtdinboxPage;
	this._doc = gtdinboxPage.doc;
	this._labels = this._gtdinboxPage._labels;
	this._showHiders = [];
	this._eventObservers = new EventObservers(this);
	
	this.create();
};
Dashboard.prototype.create = function(){
try{
	var elSearchRow = this._gtdinboxPage.gmailDOM.element("search-row");
	
	this.el = this._doc.createElement("DIV");
		this.el.className = "dashboard";	
		this.el.style.display = "none";
	
	this.elInner = this._doc.createElement("DIV");
	this._eventObservers.observe(this.elInner, "mouseup", this._clickLink, false);
	this.elInnerMain = this._doc.createElement("DIV");
		this.elInnerMain.className = "main";
	this.elInner.appendChild( this.elInnerMain );
	this.elInnerSidebar = this._doc.createElement("DIV");
		this.elInnerSidebar.className = "sidebar";
	this.elInner.appendChild( this.elInnerSidebar );
	var elFooter = this._doc.createElement("DIV");
		elFooter.className = "dashboard-footer";
	this.elInner.appendChild( elFooter );
			
	this._showHider = new Showhider(this._gtdinboxPage, "dashboard", {doc: this._doc, elParent:this.el, title:this._gtdinboxPage.stringBundle.getString("Dashboard"), elContent: this.elInner});	
	this._showHider.addEventHandler(this, "show", this.loadExternalRSS);
	this._showHider.addEventHandler(this, "toggle", this.showHide);

	
	var settings = this._gtdinboxPage.settings;
	var statusPrefix = settings.labels.types.Statuses.prefix;
	var statusDefaults = settings.labels.types.Statuses.defaults;
	
	// Tasks
	var links = [];
	var appendCommandsShow = [false, false];
	
	var statusLabels = this._labels.getLabelsArray("Statuses");
	var statusStr = "";
	var statusFinished = this._gtdinboxPage.settings.labels.types.Statuses.prefix + this._gtdinboxPage.settings.labels.types.Statuses.defaults.Finished;
	for( var i = 0; i < statusLabels.length; i++ ) if(statusLabels[i]!=statusFinished) statusStr += ((i>0)? " OR ":"") + GIPROTOTYPE.searchableLabel(statusLabels[i]);
	links.push( [this._gtdinboxPage.stringBundle.getString("Dashboard.Tasks.ShowAllTasks"), statusStr, "dashboard.tasks.showAllTasks", null, appendCommandsShow] );
	
	var labels = GIPROTOTYPE.clone(this._labels.getLabelsArray("Statuses"));	
	var settingsStatus = this._gtdinboxPage.settings.labels.types.Statuses;
	for( d in settingsStatus.defaults ){ // Process defaults
		var label = settingsStatus.prefix + settingsStatus.defaults[d];
		for( var i = 0; i < labels.length; i++ ){
			if( labels[i]==(settingsStatus.prefix + settingsStatus.defaults["SomeDay"]) ){	// for review
				labels.splice(i,1);
				i--;
			}else if( labels[i]==label ){
				links.push( [label.replace(settingsStatus.prefix,""), GIPROTOTYPE.searchableLabel(label), "dashboard.tasks." + label.replace(settingsStatus.prefix,""), label, true] );
				labels.splice(i,1);
				i--;
			}
		}
	}
	for( var i = 0; i < labels.length; i++ ){	// And the rest
		var label = labels[i];
		links.push( [label.replace(settingsStatus.prefix,""), GIPROTOTYPE.searchableLabel(label), "dashboard.tasks." + label.replace(settingsStatus.prefix,""), label, true] );
	}
	
	
	/*
	links.push( [this._gtdinboxPage.stringBundle.getString("Dashboard.Tasks.NextActions"), GIPROTOTYPE.searchableLabel(statusPrefix + statusDefaults.NextAction), "dashboard.tasks.next-actions", statusPrefix + statusDefaults.NextAction]);	
	links.push( [this._gtdinboxPage.stringBundle.getString("Dashboard.Tasks.Actions"), GIPROTOTYPE.searchableLabel(statusPrefix + statusDefaults.Action), "dashboard.tasks.actions", statusPrefix + statusDefaults.Action]);
	links.push( [this._gtdinboxPage.stringBundle.getString("Dashboard.Tasks.WaitingOn"), GIPROTOTYPE.searchableLabel(statusPrefix + statusDefaults.WaitingOn), "dashboard.tasks.waiting-on", statusPrefix + statusDefaults.WaitingOn]);
	*/

	links.push( [this._gtdinboxPage.stringBundle.getString("Dashboard.Tasks.Personal"), "<gtdinbox.personalemail> " + GIPROTOTYPE.searchableLabel(statusPrefix + statusDefaults.Action), "dashboard.tasks.personal-actions", null, appendCommandsShow] );
	this.addSection(this.elInnerMain, this._gtdinboxPage.stringBundle.getString("Dashboard.Tasks"), links);	
	
	// Review
	links.length = 0;
	links.push( [this._gtdinboxPage.stringBundle.getString("Dashboard.Reviews.SomedayMaybe"), GIPROTOTYPE.searchableLabel(statusPrefix + statusDefaults.SomeDay), "dashboard.review.someday-maybe", statusPrefix + statusDefaults.SomeDay, true]);
	
	//var labels = this._labels.getLabelsArray();
	//var excLabels = "";
	//for( var i = 0; i < labels.length; i++ ) excLabels += "-" + GIPROTOTYPE.searchableLabel(labels[i]) + " AND ";
	//excLabels = "(" + excLabels + ")";
	//links.push( ["All Unlabelled", excLabels, "dashboard.review.unlabelled"]);
	
	var d = (new Date()).valueOf();
	var day = 1000*60*60*24;
	links.push( [this._gtdinboxPage.stringBundle.getString("Dashboard.Reviews.Recent"), "after:" + GIPROTOTYPE.searchDate(d-(day*7)) + " " + GIPROTOTYPE.searchableLabel(statusPrefix + statusDefaults.Action), "dashboard.review.recent-actions", null, appendCommandsShow]);
	links.push( [this._gtdinboxPage.stringBundle.getString("Dashboard.Reviews.OneWeekOld"), "before:" + GIPROTOTYPE.searchDate(d-(day*7)) + " " + GIPROTOTYPE.searchableLabel(statusPrefix + statusDefaults.Action), "dashboard.review.1week-old-actions", null, appendCommandsShow]);
	links.push( [this._gtdinboxPage.stringBundle.getString("Dashboard.Reviews.OneMonthOld"), "before:" + GIPROTOTYPE.searchDate(d-(day*31)) + " " + GIPROTOTYPE.searchableLabel(statusPrefix + statusDefaults.Action), "dashboard.review.1month-old-actions", null, appendCommandsShow]);
	links.push( [this._gtdinboxPage.stringBundle.getString("Dashboard.Reviews.ThreeMonthsOld"), "before:" + GIPROTOTYPE.searchDate(d-(day*63)) + " " + GIPROTOTYPE.searchableLabel(statusPrefix + statusDefaults.Action), "dashboard.review.3month-old-actions", null, appendCommandsShow]);
	links.push( [this._gtdinboxPage.stringBundle.getString("Dashboard.Reviews.FinishedLast3Months"), "after:" + GIPROTOTYPE.searchDate(d-(day*63)) + " " + GIPROTOTYPE.searchableLabel(statusPrefix + statusDefaults.Finished), "dashboard.review.3month-finished", null, appendCommandsShow]);
	
	this.addSection(this.elInnerMain, this._gtdinboxPage.stringBundle.getString("Dashboard.Reviews"), links);	
	
	var elGTDSection = this.addSection(this.elInnerMain, this._gtdinboxPage.stringBundle.getString("Dashboard.Labels"));	//TODO language
	this.elGTDContainer = this._doc.createElement("DIV");
	elGTDSection.appendChild( this.elGTDContainer );
	this.refreshGTDLabels();
	
	
	var elFooter = this._doc.createElement("DIV");
		elFooter.className = "dashboard-main-footer";
	this.elInnerMain.appendChild( elFooter );
	
	
	var elSidebarTitle = this._doc.createElement("DIV");
		elSidebarTitle.className = "title";
		elSidebarTitle.innerHTML = "<a href='http://productivefirefox.com' target='_blank'>Productive Firefox</a>";
	this.elInnerSidebar.appendChild(elSidebarTitle);
	var elTab = this._doc.createElement("DIV");
	this.elInnerSidebar.appendChild(elTab);
	var elTabTitle = this._doc.createElement("DIV");
		elTabTitle.innerHTML = "<a href='http://blog.productivefirefox.com' target='_blank'>" + this._gtdinboxPage.stringBundle.getString("Dashboard.ProductiveFirefox.LatestNews") + "</a>";	
		elTabTitle.className = "accordionTabTitle";
	elTab.appendChild(elTabTitle);
	this.elTabContentBlog = this._doc.createElement("DIV");
		this.elTabContentBlog.innerHTML = "Latest News Content";	
		this.elTabContentBlog.className = "accordionTabContent";
	elTab.appendChild(this.elTabContentBlog);
	
	var elTab = this._doc.createElement("DIV");
	this.elInnerSidebar.appendChild(elTab);
	var elTabTitle = this._doc.createElement("DIV");
		elTabTitle.innerHTML = "<a href='http://forum.productivefirefox.com' target='_blank'>" + this._gtdinboxPage.stringBundle.getString("Dashboard.ProductiveFirefox.LatestChatter") + "</a>";	
		elTabTitle.className = "accordionTabTitle";
	elTab.appendChild(elTabTitle);
	this.elTabContentForum = this._doc.createElement("DIV");
		this.elTabContentForum.innerHTML = "content";	
		this.elTabContentForum.className = "accordionTabContent";
	elTab.appendChild(this.elTabContentForum);
	
	
	elSearchRow.parentNode.insertBefore(this.el, elSearchRow.nextSibling);
	this.el.style.display = "";
	
	var accordion = new Rico.Accordion( this.elInnerSidebar, {document:this._doc, panelHeight:'80'} );	// panelHeight:'80px'
	accordion.showTabByIndex(0);
	
	this._labels.addEventHandler( this, "refresh-labels", this.refreshGTDLabels );
	
	if( this._showHider.show() ) this.loadExternalRSS();
	
}catch(e){
	if( GTDDEBUGMODE ) alert("Dashboard create\n" + e.toString());
}
};


Dashboard.prototype._appendCommands = function(elLink, cannotPopout, canExpand){
	var fAttrib = function(el){
			el.setAttribute("gtdSearch", elLink.getAttribute("gtdSearch"));
			el.setAttribute("gtdName", elLink.getAttribute("gtdName"));
			el.setAttribute("gtdLabelName", elLink.getAttribute("gtdLabelName"));
			el.setAttribute("gtdType", elLink.getAttribute("gtdType"));
			el.setAttribute("email", elLink.getAttribute("email"));
		};
		
	// Compartmentalise the old link inner html
	var elContent = this._doc.createElement("DIV");
		elContent.className = "body";
		elContent.innerHTML = elLink.innerHTML;
		fAttrib(elContent);
	elLink.innerHTML = "";
	elLink.appendChild( elContent );
	
	var elCmds = this._doc.createElement("DIV");
		elCmds.className = "commands";
	elLink.appendChild( elCmds );
		
	if( !cannotPopout ){
		var elPopout = this._doc.createElement("IMG");
			elPopout.className = "async-popuper";
			elPopout.src = "chrome://gtdinbox/skin/popout.png";
			elPopout.title = this._gtdinboxPage.stringBundle.getString("FilterPopup.tooltip.Open");	
			fAttrib(elPopout);
		elCmds.appendChild( elPopout );
	}
		
	if( elLink.getAttribute("gtdName") && canExpand ){
		var elExpander = this._doc.createElement("IMG");
			elExpander.className = "expander";
			elExpander.src = "chrome://gtdinbox/content/filter-extend.png";
			elExpander.title = this._gtdinboxPage.stringBundle.getString("FilterPopup.tooltip.Drill");	
		elCmds.appendChild( elExpander );
		fAttrib(elExpander);
	}
	
	var elClear = this._doc.createElement("DIV");
	elClear.style.clear = "both";
	elLink.appendChild( elClear );
};
Dashboard.prototype._clickExtend = function(el){
	// Use the line-item to generate new popup
try{
	if( this._filterChild ){	// turn off
		this._filterChild.destroy();
		this._filterChild = null;
		//if( this._filterChildEl==el ) return;
	}
	
	var type = el.getAttribute("gtdType");
	var name = (type=="Contact")? [el.getAttribute("gtdName"),el.getAttribute("gtdName")] : el.getAttribute("gtdLabelName");
	var parentSearch = el.getAttribute("gtdSearch");
	this._filterChild = new FilterPopupUI( this._gtdinboxPage, name, type, el, [], [], parentSearch );
	this._filterChild.popup(el,{location:'right'});
	this._filterChildEl = el;
}catch(e){
	if( GTDDEBUGMODE ) alert("Dashboard clickExtend\n" + e.toString());
}
};

Dashboard.prototype.loadExternalRSS = function(){
try{
	if( this._loadedExternalRSS ) return;
	this._loadedExternalRSS = true;

	var url = "http://www.google.com/uds/Gfeeds?v=1.0&output=json&q=" + encodeURIComponent("http://feeds.feedburner.com/ProductiveFirefox");
	var callback = GIPROTOTYPE.bind(this, function(jsonStr){
			var rss = json.parse(jsonStr);
			if( rss.responseData ){
				var entries = rss.responseData.feed.entries;
				var el = this._doc.createElement("UL");
				for( var i = 0; i < entries.length; i++ ){
					var elLi = this._doc.createElement("LI");
					elLi.innerHTML = "<a href=\"" + entries[i].link + "\" target='_blank'>" + entries[i].title + "</a>";
					elLi.title = entries[i].contentSnippet;
					el.appendChild( elLi );
				}
				this.elTabContentBlog.innerHTML = "";
				this.elTabContentBlog.appendChild(el);
			}
		});
	this._loadExternalRSSRequest(url, callback);
		
	var url = "http://www.google.com/uds/Gfeeds?v=1.0&output=json&q=" + encodeURIComponent("http://feeds.feedburner.com/ProductiveFirefoxChatter");
	var callback = GIPROTOTYPE.bind(this, function(jsonStr){
			var rss = json.parse(jsonStr);
			if( rss.responseData ){
				var entries = rss.responseData.feed.entries;
				var el = this._doc.createElement("UL");
				for( var i = 0; i < entries.length; i++ ){
					var elLi = this._doc.createElement("LI");
					elLi.innerHTML = "<a href=\"" + entries[i].link + "\" target='_blank'>" + entries[i].title + "</a>";
					elLi.title = entries[i].contentSnippet;
					el.appendChild( elLi );
				}
				this.elTabContentForum.innerHTML = "";
				this.elTabContentForum.appendChild(el);
			}
		});
	this._loadExternalRSSRequest(url, callback);
	
}catch(e){
	if( GTDDEBUGMODE ) alert("Dashboard loadExternalRSS\n" + e.toString());
}
};
Dashboard.prototype._loadExternalRSSRequest = function(url, callback){
	var req = new XMLHttpRequest();
	req.open('GET', url, true);
	req.onreadystatechange = GIPROTOTYPE.bind(this, function(aEvt){
		try{
		if (req.readyState==4) {
			if( req.status==200 ){
				callback(req.responseText);
			}
		}
		}catch(e){
			if( GTDDEBUGMODE ) alert("Dashboard loadExternalRSS statechange\n" + e.toString());
		}
	});
	req.send(null);
};

Dashboard.prototype.refreshGTDLabels = function(){
try{
	for( var i = this.elGTDContainer.childNodes.length - 1; i >= 0; i-- ){
		this.elGTDContainer.removeChild( this.elGTDContainer.childNodes[i] );
	}
	
	var settings = this._gtdinboxPage.settings;
	for( t in settings.labels.types ){
		if( t!="Statuses" ){
			var elLabels = this._labels.getLabelsEl(t);
			var showHider = new Showhider(this._gtdinboxPage, "dashboard-gtd-" + t, {doc:this._doc, type:"attach", el:elLabels, titleClass:"title", show:false});
			elLabels.style.display = (showHider.elContent.innerHTML.length==0)? "none" : "";
			this.elGTDContainer.appendChild( elLabels );
			this._showHiders.push( showHider );
			
			// Add in command buttons:
			var els = elLabels.getElementsByTagName("*");
			for( var i = els.length - 1; i>=0; i-- ){
				if( els[i].className=="title" ) els[i].innerHTML = title;
				if( els[i].getAttribute("gtdLabelName") ){
					els[i].setAttribute("gtdSearch", GIPROTOTYPE.searchableLabel(els[i].getAttribute("gtdLabelName"))); 
					this._appendCommands(els[i], false, true);
				}
			}
		}
	}
}catch(e){
	if( GTDDEBUGMODE ) alert("Dashboard refreshGTDLabels\n" + e.toString());
}
};

Dashboard.prototype.addSection = function(elParent, title, links){
try{
	var el = this._doc.createElement("DIV");
		el.className = "dashboard-section";
	if( elParent ) elParent.appendChild( el );
	
	var elTitle = this._doc.createElement("SPAN");
		elTitle.className = "title";
	elTitle.innerHTML = title;
	el.appendChild( elTitle );
	
	if( !links ){
	}else if( links.nodeName ){	// element
		el.appendChild( links );
	}else{	// array
		var elList = this._doc.createElement("DIV");	// formerly UL
			elList.className = "unordered-list";
		el.appendChild( elList );
		
		for( var i = 0; i < links.length; i++ ){
			var elLi = this._doc.createElement("DIV");	// formerly LI
				elLi.className = "list-item label";
			elLi.innerHTML = links[i][0];
			elLi.setAttribute("gtdSearch", links[i][1]);
			elLi.setAttribute("gtdId", links[i][2]);
			if( links[i][3] ){	// it's just a label
				elLi.setAttribute("gtdLabelName", links[i][3] );
				elLi.setAttribute("gtdName", links[i][3] );
			}
			elList.appendChild( elLi );
			if( links[i][4] ){	// append commands
				if( links[i][4] instanceof Array ){
					this._appendCommands(elLi, links[i][4][0], links[i][4][1]);
				}else{
					this._appendCommands(elLi, false, true);
				}
			}
		}
	}
	
	return el;	
}catch(e){
	if( GTDDEBUGMODE ) alert("Dashboard addSection\n" + e.toString());
}
};

Dashboard.prototype._clickLink = function(event){
try{
	if( event.button!=0 ) return;
	
	
	var el = GIPROTOTYPE.element(event);
	
	if( el.nodeName=="IMG" && el.className=="expander" ){
		this._clickExtend(el);
		GIPROTOTYPE.stop(event);
		return;
	}
	
	var searchStr = el.getAttribute("gtdSearch");
	if( !searchStr ){
		var label = {name:el.getAttribute("gtdName"), labelname:el.getAttribute("gtdLabelName"), 'el':el}
		if( label.labelname ){
			this._gtdinboxPage.search(GIPROTOTYPE.searchableLabel(label.labelname));
		}
		return;
	}
	GIPROTOTYPE.stop(event);
	
	if( searchStr.indexOf("<gtdinbox.personalemail>")>-1 ){
		var personalSearch = GIPROTOTYPE.restrictSearchToUser(this._gtdinboxPage._environment.emails);
		searchStr = searchStr.replace( "<gtdinbox.personalemail>", personalSearch );
	}
	
	this._gtdinboxPage.search(searchStr);
}catch(e){
	if( GTDDEBUGMODE ) alert("Dashboard _clickLink\n" + e.toString());
}
};

Dashboard.prototype.showHide = function(){
	// Move the contacts iframe to be below the dashboard; since it can't move itself
	
	if( !this._elIframe ){
		this._elIframe = this._gtdinboxPage.gmailDOM.element("contacts-iframe", null, this._gtdinboxPage.gmailDOM.element("document"));
		if( !this._elIframe ) return;
	}
	
	var offset = GIPROTOTYPE.cumulativeOffset(this.el);
	var dims = GIPROTOTYPE.getDimensions(this.el, this._doc);
	this._elIframe.style.top = (offset[1] + dims.height + 3) + "px";
};

Dashboard.prototype.destroy = function(){
	this._eventObservers.destroy();
	if( this.el && this.el.parentNode ) this.el.parentNode.removeChild(this.el);
	this._showHider.destroy();

	this._labels = null;
	
	for( var i = 0; i < this._showHiders.length; i++ ){
		this._showHiders[i].destroy();
	}
	
	this.el = null;
	this._gtdinboxPage = null;
	this._doc = null;
};